import { AbEqualToOther, Derivation, DerivationonSymbolEpsilon, DerivationonTokenEOF, EqualToEqualToOther, Grammar, GrammarToken, TokenEpsilon } from "./common_lr";
import { ContainerMarkableBox } from "./ContainerMarkableBox";
import { FamilyItemsLR0 } from "./lr0";
import { FamilyItemsTableLR1 } from "./lr1";

///////////////////////////////// LR(1) /////////////////////////////////



/**
 * 项目集规范族 LALR(1) - 项目
 * 
 * A -> • B a    ⊸ $/a/b    pos = 0 ，展望符为 $ 和 a 、b
 * A ->  B • a   ⊸ $/a/b    pos = 1 ，展望符为 $ 和 a 、b
 * A ->  B a •   ⊸ $/a/b    pos = 2 ，展望符为 $ 和 a 、b
 */
export class FamilyItemsLALR1 extends FamilyItemsLR0 {
    readonly prospectSymbol: Set<GrammarToken>;
    constructor(d: Derivation, pos: number, prospectSymbol: Set<GrammarToken>) {
        super(d, pos);
        this.prospectSymbol = prospectSymbol;
    }

    static SetIsEqual(a: Set<GrammarToken>, b: Set<GrammarToken>): boolean {
        // TODO 没有考虑 null 的情况
        if (a === b) {
            return true;
        }

        if (a.size !== b.size) {
            return false;
        }

        for (let item of a) {
            if (!b.has(item)) {
                return false;
            }
        }

        return true;
    }

    equalToOther(other: FamilyItemsLALR1): boolean {
        return super.equalToOther(other)
            && FamilyItemsLALR1.SetIsEqual(this.prospectSymbol, other.prospectSymbol);
    }

    static equal(a: FamilyItemsLALR1, b: FamilyItemsLALR1) {
        return EqualToEqualToOther(a, b);
    }

    toString(): string {
        const rightList: any = [...this.dervation.right];
        rightList.splice(this.pos, 0, "•");
        return `${this.dervation.left} -> ${rightList.join(" ")}   ⊸    ${[...this.prospectSymbol].join(",")}`
    }
}


/**
 * 项目集规范族 LR(1) - 集合
 */
export class FamilyItemsSetLALR1 implements AbEqualToOther {
    readonly container: FamilyItemsLALR1[] = [];

    /**
     * 去重添加，如果重复则不添加
     * @param item 
     * @returns 成功添加返回真，否则，返回假
     */
    addItem(item: FamilyItemsLALR1): boolean {
        for (const oi of this.container) {
            if (oi.equalToOther(item)) {
                return false;
            }
        }

        this.container.push(item);
        return true;
    }

    /**
     * 比较相等， 可以通过 Hash 优化
     * @TODO Hash 优化
     */
    equalToOther(other: FamilyItemsSetLALR1): boolean {
        if (this === other) {
            return true;
        }

        if (other.container.length != this.container.length) {
            return false;
        }

        for (let idx = 0; idx < this.container.length; idx++) {
            const left = this.container[idx];
            const right = other.container[idx];
            if (!left.equalToOther(right)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 是否是同心集
     */
    static testIsSameCore()  {

    }

    // static equal(a: FamilyItemsSetLALR1, b: FamilyItemsSetLALR1) {
    //     return EqualToEqualToOther(a, b);
    // }

    toString(): string {
        return this.container.join("\n");
    }
}







/**
 * 项目集规范族 LALR(1)
 */
export class FamilyItemsTableLALR1 {
    private g: Grammar;
    constructor(g: Grammar) {
        this.g = g;
    }

    // /**
    //  * 重新计算语法相关信息
    //  */
    // ReclaculateInfo(): ContainerMarkableBox<FamilyItemsSetLALR1, GrammarToken> {
    //     FamilyItemsTableLR1.FromGrama(g);

    //     this.cachedDerivationMap = this.g.BuildDerivationMap();
    //     const firstF = this.g.CalcuateNonTerminatorFirstFunc();


    //     // 计算项目集规范组
    //     // 第一项 start d list
    //     const theFirstItemSet = this.ExtendSetFrom(
    //         firstF,
    //         [...this.cachedDerivationMap.get(this.g.s) ?? []]
    //             .map(item => new FamilyItemsLALR1(item, 0, DerivationonTokenEOF))
    //     );

    //     // map box
    //     const theMapBox = new ContainerMarkableBox<FamilyItemsSetLALR1, GrammarToken>(
    //         FamilyItemsSetLR1.equal,
    //         (a, b) => a === b,
    //         theFirstItemSet,
    //     );

    //     return theMapBox;
    // }

    // static FromGrama(g: Grammar): FamilyItemsTableLALR1 {
    //     var f = new FamilyItemsTableLALR1(g);
    //     f.ReclaculateInfo();
    //     return f;
    // }
}

